#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

// 与发送端相同的组播地址
#define MULTICAST_GROUP "239.255.1.1"
// 与发送端相同的端口号
#define PORT 9000
// 缓冲区大小
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in local_addr, sender_addr;
    struct ip_mreq multicast_request;
    socklen_t sender_len;
    char buffer[BUFFER_SIZE];

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 允许端口复用，多个接收端可以绑定到同一个端口
    int reuse = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
        perror("setsockopt SO_REUSEADDR failed");
        exit(EXIT_FAILURE);
    }

    // 初始化本地地址结构
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 绑定到所有网络接口
    local_addr.sin_port = htons(PORT);

    // 绑定套接字到本地地址
    if (bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 设置组播请求：加入组播组
    multicast_request.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
    // 设置接收接口（当前机器的IP地址）
    // 如果你在电脑1上运行接收端，使用192.168.5.128
    // 如果你在电脑2上运行接收端，使用192.168.5.129
    multicast_request.imr_interface.s_addr = inet_addr("192.168.5.129");

    // 加入组播组
    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
                  &multicast_request, sizeof(multicast_request)) < 0) {
        perror("setsockopt IP_ADD_MEMBERSHIP failed");
        exit(EXIT_FAILURE);
    }

    printf("Multicast receiver started. Listening on %s:%d\n", 
           MULTICAST_GROUP, PORT);
    printf("Press Ctrl+C to stop...\n");

    // 循环接收组播数据
    while (1) {
        sender_len = sizeof(sender_addr);
        ssize_t recv_len = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0,
                                  (struct sockaddr*)&sender_addr, &sender_len);
        
        if (recv_len < 0) {
            perror("recvfrom failed");
            exit(EXIT_FAILURE);
        }

        buffer[recv_len] = '\0';  // 确保字符串以null结尾
        printf("Received from %s:%d: %s\n", 
               inet_ntoa(sender_addr.sin_addr),
               ntohs(sender_addr.sin_port),
               buffer);
    }

    // 离开组播组（实际中不会执行到这里）
    if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
                  &multicast_request, sizeof(multicast_request)) < 0) {
        perror("setsockopt IP_DROP_MEMBERSHIP failed");
        exit(EXIT_FAILURE);
    }

    close(sockfd);
    return 0;
}
